package cmp.viewer.panels;

/************************************************
 * Displays the sTCW database tree. It's also used for browsing the mTCW databases, depending whether has a parent or not. 
 */
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.Iterator;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import jpave.query_interface.JPaveFrame;
import util.Debug.ErrorReport;
import util.methods.HostsCfg;
import util.ui.UserPrompt;
import cmp.compile.CompileMain;
import cmp.compile.panels.CompilePanel;
import cmp.compile.panels.EditSpeciesPanel;
import assem.DBConn;
import cmp.main.Globals;
import cmp.viewer.ViewerFrame;

public class DatabaseSelectPanel extends JPanel {
	private static final long serialVersionUID = 3004816148155062955L;
	
	private static final int TREE_PANEL_WIDTH = 350;
	private static final int TREE_PANEL_HEIGHT = 300;
    
	public DatabaseSelectPanel(String prefixold, String prefix, EditSpeciesPanel parentPanel) {
		HostsCfg hostcfg = new HostsCfg();
		Vector<String> names = CompilePanel.loadDBListFromHost(hostcfg.host, 
		        hostcfg.user, hostcfg.pass, prefixold, prefix);
		allDBs = new Vector<DatabaseData> ();
		for (String db : names)
		{
			allDBs.add(new DatabaseData(hostcfg.host, db));
		}
		
		theParentPanel = parentPanel;
	/*	Vector<String> hosts = new Vector<String>();
		hosts.add(hostcfg.host);
		allDBs = new Vector<DatabaseData> ();
		Iterator<String> hostIter = hosts.iterator();
		while(hostIter.hasNext()) {
			String hostName = hostIter.next();
			String [] userData = CompilePanel.loadUserDataForHost(hostName);
			// CAS 4/24/13
			if (userData==null || userData[0] == null || userData[0].equals("") || 
					userData[0] == null || userData[0].equals("")) 
						ErrorReport.die("Problem with hosts, user or password in HOSTS.cfg");
			
			Vector<String> names = CompilePanel.loadDBListFromHost(hostName, 
			        userData[0], userData[1], prefixold, prefix);
			Iterator<String> nameIter = names.iterator();
			while(nameIter.hasNext()) {
				String name = nameIter.next();
				allDBs.add(new DatabaseData(hostName, name));
			}
		}*/
		setBackground(Globals.BGCOLOR);
		add(createTreePanel());
	}
	private JPanel getInstance() { return this; }
	
	//Tree that contains all available assemblies
	private JPanel createTreePanel() {
		JPanel thePanel = new JPanel();
		thePanel.setLayout(new BoxLayout(thePanel, BoxLayout.PAGE_AXIS));
		thePanel.setMinimumSize(new Dimension(TREE_PANEL_WIDTH, TREE_PANEL_HEIGHT));
		thePanel.setBackground(Globals.BGCOLOR);
		if(allDBs.size() > 0)
		{
			//Create the tree
			Iterator<DatabaseData> iter = allDBs.iterator();
			DatabaseData temp = iter.next();

			DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Available Databases");
			DefaultMutableTreeNode header = new DefaultMutableTreeNode(temp.getHost());

			boolean done = false;
			while(!done) {
				if(temp.getHost().equals(header.getUserObject())) {
					header.add(new DefaultMutableTreeNode(temp.getDBName()));
					if(iter.hasNext())
						temp = iter.next();
					else
						done = true;
				}
				else {
					rootNode.add(header);
					header = new DefaultMutableTreeNode(temp.getHost());
				}
			}
			rootNode.add(header);
			theTree = new JTree(rootNode);

			theTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
			theTree.setToggleClickCount(1);
			((DefaultTreeCellRenderer) theTree.getCellRenderer()).setLeafIcon(null);
			if (theTree.getRowCount() == 1)
				theTree.expandRow(0);

			theTree.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					TreePath path = theTree.getSelectionPath();
					if (path != null) {
						int depth = path.getPathCount();
						if (e.getClickCount() == 2 && depth > 2) {
							keepClicked();
							return;
						}
						btnKeep.setEnabled(depth > 2);
						btnGetState.setEnabled(depth > 2);
					}
                                //update add and remove buttons
				}
			});

			JScrollPane treeView = new JScrollPane(theTree);
			treeView.setPreferredSize(thePanel.getMinimumSize());
			thePanel.add(treeView);
			
			//Notify user of the number of available assemblies
			txtNumAssemblies = new JTextField(1);
			Dimension d = treeView.getPreferredSize();
			Dimension d2 = txtNumAssemblies.getPreferredSize();
			txtNumAssemblies.setPreferredSize(new Dimension(d.width, d2.height));
			txtNumAssemblies.setEditable(false);
			txtNumAssemblies.setHorizontalAlignment(JTextField.CENTER);
			txtNumAssemblies.setBorder(BorderFactory.createEmptyBorder());
			txtNumAssemblies.setBackground(Globals.BGCOLOR);
			thePanel.add(Box.createVerticalStrut(5));
			thePanel.add(txtNumAssemblies);
			thePanel.add(Box.createVerticalStrut(10));
			txtNumAssemblies.setText("Databases available: " + allDBs.size());
                    
			String buttonLabel;
			if(theParentPanel == null) 
				buttonLabel = "Launch";
			else
				buttonLabel = "Keep";
			
			JPanel buttonPanel = CompilePanel.getPanel(true);
			
			JPanel row = CompilePanel.getPanel(true);
			row.setAlignmentX(Component.CENTER_ALIGNMENT);
			
			btnKeep = new JButton(buttonLabel);
			btnKeep.setEnabled(false);
			if (theParentPanel == null) btnKeep.setBackground(Globals.LAUNCHCOLOR);
			else btnKeep.setBackground(Globals.BGCOLOR);
			btnKeep.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					keepClicked();
				}
			});
			row.add(btnKeep);
			btnGetState = new JButton("Overview");
			btnGetState.setBackground(Globals.LAUNCHCOLOR);
			btnGetState.setEnabled(false);
			btnGetState.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					if(theParentPanel == null)
						showStateCMPPAVEDB();
					else 
						showStatePAVEDB();
				}
			});
			row.add(Box.createHorizontalStrut(10));
			row.add(btnGetState);
			row.setMaximumSize(row.getPreferredSize());
			row.setMinimumSize(row.getPreferredSize());

			if(theParentPanel != null) {
				btnDiscard = new JButton("Discard");
				btnDiscard.setBackground(Globals.BGCOLOR);
				btnDiscard.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						theParentPanel.setMainPanelVisible(true);
						setVisible(false);
					}
				});
				row.add(Box.createHorizontalStrut(10));
				row.add(btnDiscard);
			}			
			else {
				// TODO If a Launch and Overview have occurred, and the
				// Launch was exited, then it does not go back to prompt
				// because it thinks the Overview is still open
				btnClose =new JButton("Exit");
				btnClose.setBackground(Globals.BGCOLOR);
				btnClose.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						//Position 0 is the select panel
						ViewerFrame.closeFrame(0);		
						if (ViewerFrame.getFrameCount() == 0)
							System.exit(0);
					}
				});
				
				row.add(Box.createHorizontalStrut(10));
				row.add(btnClose);
				
				btnCloseAll = new JButton("Exit all");
				btnCloseAll.setBackground(Globals.BGCOLOR);
				btnCloseAll.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						ViewerFrame.closeAllFrames();
						System.exit(0); // CAS 4/10/13
					}
				});
				row.add(Box.createHorizontalStrut(10));
				row.add(btnCloseAll);
			}
						
			buttonPanel.add(Box.createHorizontalGlue());
			buttonPanel.add(row);
			buttonPanel.add(Box.createHorizontalGlue());
			
			thePanel.add(buttonPanel);
		}

		return thePanel;
	}
	private void showStateCMPPAVEDB() {
		try {
			String val = null;
			HostsCfg hosts = new HostsCfg();
			
			DatabaseData data = getSelection();
			//String [] userData = CompilePanel.loadUserDataForHost(data.getHost());
			
			if(!DBConn.checkMysqlDB("Show State Multi", hosts.host, data.getDBName(), hosts.user, hosts.pass))
				val = "No database available";
			
			if(val == null) {
				DBConn conn = new DBConn(hosts.host, data.getDBName(), hosts.user, hosts.pass);
				ResultSet rset = conn.executeQuery("SELECT summary FROM info");
				
				if(rset.first()) {
					val = rset.getString(1);
				}
				rset.close();
				conn.close();
			}
			UserPrompt.displayInfoMonoSpace(null, "Overview for " + data.getDBName(), val.split("\n"), false, true);
		}
		catch(Exception e) {
			ErrorReport.prtReport(e, "Error getting project state");
		}
	}
	private void showStatePAVEDB() {
		try {
			String val = null;
			HostsCfg hosts = new HostsCfg();
			DatabaseData data = getSelection();
			//String [] userData = CompilePanel.loadUserDataForHost(data.getHost());
			
			if(!DBConn.checkMysqlDB("Show State DBs ", hosts.host, data.getDBName(), hosts.user, hosts.pass))
				val = "No database available";
			
			if(val == null) {
				DBConn conn = new DBConn(hosts.host, data.getDBName(), hosts.user, hosts.pass);
				ResultSet rset = conn.executeQuery("SELECT pja_msg FROM assem_msg where AID=1");
				
				if(rset.first()) {
					val = rset.getString(1);
					if (val != null && val.length() <= 5) {
						val = "Launch viewSingleTCW to update the Overview";
					}
				}
				rset.close();
				if(val == null) {
					rset = conn.executeQuery("SELECT msg FROM assem_msg where AID=1");
					if(rset.first())
						val = rset.getString(1);
					rset.close();
					if(val == null) {
						Vector<String> libIDs = new Vector<String> ();
						rset = conn.executeQuery("SELECT libid FROM library");
						while(rset.next()) 
							libIDs.add(rset.getString(1));
						rset.close();
						
						rset = conn.executeQuery("SELECT assemblydate FROM assembly");
						String assemDate = null;
						if(rset.first())
							assemDate = rset.getString(1);
						rset.close();
						
						val = "Loaded:";
						for(int x=0; x<libIDs.size(); x++) {
							val += " " + libIDs.get(x);
						}
						val+= "\n";
						
						if(assemDate == null)
							val+= "Assembly not completed\n";
						else
							val+= "Assembly Finished: " + assemDate + "\n";
						val+= "Annotation: none";
					}
				}
				conn.close();
			}
			UserPrompt.displayInfoMonoSpace(null, "Overview for " + data.getDBName(), val.split("\n"), false, true);
		}
		catch(Exception e) {
			ErrorReport.prtReport(e, "Error getting project state");
		}
	}

	private void keepClicked() {
		if(theParentPanel == null)
			launchSelection();
		else {
			DatabaseData data = getSelection();
			theParentPanel.setHost(data.getHost());
			String db = data.getDBName();
			theParentPanel.setDBName(db);
			theParentPanel.setRemark(db.substring(5)); 
			
			try {
				DBConn conn = CompileMain.getDBConnection(data.getHost(), data.getDBName());
				ResultSet rset = conn.executeQuery("SELECT * FROM assem_msg where AID=1 LIMIT 1");
				
				ResultSetMetaData rsmd = rset.getMetaData();
				boolean bIsPeptide = false;
				int nCols = rsmd.getColumnCount();
				for(int x=1; x<=nCols && !bIsPeptide; x++) {
					if(rsmd.getColumnName(x).equals("peptide"))
						bIsPeptide = true;
				}
				theParentPanel.setPeptideDB(bIsPeptide);
				rset.close();
				
				// CAS 12/22/14 add popup messages 
				rset = conn.executeQuery("SELECT assemblyid FROM assembly");
				if(rset.next()) {
					String asm = rset.getString(1);
					theParentPanel.setAssemblyName(asm);
					String prefix = asm;
					if (asm.length()>3) prefix = asm.substring(0,3);
					else if (asm.length()==0) {
						System.err.println("WARN: no ID from database " + db);
						JOptionPane.showMessageDialog(null, "No ID from database " + db 
								+ "It may not be complete. " +
								"\nYou must beable to view it in viewSingleTCW to use it here.", 
								"Warn", JOptionPane.PLAIN_MESSAGE);
						if (db.length()>3) prefix = db.substring(0,3);
						else prefix = db;
					}
					theParentPanel.setPrefix(prefix); 
				}
				else {
					System.err.println("ERROR: no ID from database " + db);
					System.err.println("   Did you Instantiate? That is necessary.");
					JOptionPane.showMessageDialog(null, "No ID from database " + db 
							+ "\nYou must 'Instantiate' in runSingleTCW. ", 
							"Error", JOptionPane.PLAIN_MESSAGE);
				}
			}
			catch(Exception e) {
				ErrorReport.prtReport(e, "Error validating database");
				JOptionPane.showMessageDialog(null, "Error validating" + db 
						+ "\nYou must be able to view it in viewSingleTCW to use it here", 
						"Error", JOptionPane.PLAIN_MESSAGE);
			}
			theParentPanel.setMainPanelVisible(true);
			setVisible(false);
		}
	}

	private DatabaseData getSelection() {
		DatabaseData retVal = null;
        TreePath path = theTree.getSelectionPath();
        DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
        DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)node.getParent();
        
        Iterator<DatabaseData> iter = allDBs.iterator();
        while(iter.hasNext() && retVal == null) {
                DatabaseData temp = iter.next();
                if(temp.getDBName().equals(node.getUserObject()) && temp.getHost().equals(parentNode.getUserObject()))
                        retVal = temp;
        }
        return retVal;
	}
	private void launchSelection() {
        DatabaseData data = getSelection();
        ViewerFrame theFrame = new ViewerFrame(data.getHost(), data.getDBName(), false, null, null);
        theFrame.setVisible(true);
	}
	
	private class DatabaseData {
		public DatabaseData(String host, String name) {
			strHost = host;
			strDBName = name;
		}
		public String getHost() { return strHost; }
		public String getDBName() { return strDBName; }
		
		private String strHost = "";
		private String strDBName = "";
	}

	//Data vars
	private Vector<DatabaseData> allDBs = null;
	private EditSpeciesPanel theParentPanel = null;
	private JTree theTree = null;
	private JTextField txtNumAssemblies = null;
	private JButton btnKeep = null;
	private JButton btnDiscard = null;
	private JButton btnGetState = null;
	private JButton btnClose = null;
	private JButton btnCloseAll = null;
}